// @Author miaoqing
// @Date 2024/03/29 14:20:00
// @Desc
package network

import (
	"core/component/logger"
	"errors"
	"github.com/xtaci/kcp-go"
	"net"
	"os"
	"reflect"
	"runtime/debug"
	"sync"
	"sync/atomic"
	"time"
)

type KcpServer struct {
	tcpWgs    sync.WaitGroup
	NewClient func(conn net.Conn) IConn
	ln        *kcp.Listener
	wgLn      sync.WaitGroup
	conns     *sync.Map //map[net.Conn]net.Conn
	counter   int64
	idCounter int64
	pid       int64
}

func (kcpSrv *KcpServer) Init(addr string) {
	ln, err := kcp.Listen(addr)
	if err != nil {
		return
	}
	kcpSrv.conns = &sync.Map{}
	kcpSrv.ln = ln.(*kcp.Listener)
	kcpSrv.counter = 1
	kcpSrv.idCounter = 1
	kcpSrv.pid = int64(os.Getpid())
	logger.Infof("KcpServer 启动成功 Addr:%v", ln.Addr())
}

func (kcpSrv *KcpServer) Run() {
	defer func() {
		if err := recover(); err != nil {
			logger.Error("[net] panic", err, "\n", string(debug.Stack()))
		}
	}()

	kcpSrv.wgLn.Add(1)
	defer kcpSrv.wgLn.Done()
	var tempDelay time.Duration
	for {
		conn, err := kcpSrv.ln.AcceptKCP()
		if err != nil {
			var ne net.Error
			if errors.As(err, &ne) && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				logger.Warningf("accept error: %v; retrying in %v", err, tempDelay)
				time.Sleep(tempDelay)
				continue
			}
			return
		}
		tempDelay = 0

		if atomic.LoadInt64(&kcpSrv.counter) >= MaxConnNum {
			conn.Close()
			logger.Warning("too many connections %v", atomic.LoadInt64(&kcpSrv.counter))
			continue
		}

		conn.SetNoDelay(1, 10, 2, 1)
		conn.SetStreamMode(true)
		conn.SetWindowSize(4096, 4096)
		conn.SetReadBuffer(4 * 1024 * 1024)
		conn.SetWriteBuffer(4 * 1024 * 1024)
		conn.SetACKNoDelay(true)
		client := kcpSrv.NewClient(conn)
		kcpSrv.createNewConn(conn, client)
		logger.Infof("连接到Kcp Addr:%v", conn.RemoteAddr())

		kcpSrv.tcpWgs.Add(1)
		go func() {
			client.Run()

			kcpSrv.removeConn(conn, client)
			kcpSrv.tcpWgs.Done()
		}()
	}
}

func (kcpSrv *KcpServer) removeConn(conn net.Conn, client IConn) {
	client.Close()
	atomic.AddInt64(&kcpSrv.counter, -1)
	kcpSrv.conns.Delete(conn)
}

func (kcpSrv *KcpServer) createNewConn(conn net.Conn, client IConn) {
	atomic.AddInt64(&kcpSrv.counter, 1)
	kcpSrv.conns.Store(conn, conn)
	nowTime := time.Now().Unix()
	idCounter := atomic.AddInt64(&kcpSrv.idCounter, 1)
	ccid := (nowTime << 32) | (kcpSrv.pid << 24) | idCounter
	v := reflect.ValueOf(client).Elem()
	v.FieldByName("ConnID").Set(reflect.ValueOf(ccid))
	client.OnConnect() // 去找实现的功能
}

func (kcpSrv *KcpServer) Close() {
	kcpSrv.ln.Close()
	kcpSrv.wgLn.Wait()

	kcpSrv.conns.Range(func(key, value any) bool {
		conn, ok := value.(net.Conn)
		if !ok {
			return true
		}
		conn.Close()
		return true
	})
	kcpSrv.conns = &sync.Map{}

	kcpSrv.tcpWgs.Wait()
}
